package it.tcon.xbeedriver;


import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.log4j.Logger;
import com.rapplogic.xbee.api.zigbee.ZNetNodeIdentificationResponse.DeviceType;

public class XBeeNodeList {
	
	private ConcurrentHashMap<String, XBeeNode> list;
	private XBeeNode coordinator;
	transient private Logger logger = Logger.getLogger(XBeeNodeList.class);
	public XBeeNodeList(){
		list = new ConcurrentHashMap<String, XBeeNode>();
	}
	/**
	 * Add an XBeeNode to the device list. You can add a node only if you know the address of the device.
	 * @param node The node to add.
	 * @throws XBeeNodeException If the node is <tt>null</tt> or the node address is <tt>null</tt> than an XBeeNodeException is thrown
	 */
	public void addNode(XBeeNode node) throws XBeeNodeException{
		
		if(node != null && node.getAddress64String() != null)
			this.addNode(node.getAddress64String(),node);
		else
			logger.debug("Address of this node is null");
		
	}
	/**
	 * Add an XBeeNode to the device list specifing the node address in form of string.
	 * @param address The address in form of string
	 * @param node The node object
	 * @throws XBeeNodeException if the node is already on list an <tt>NodeAlreadyOnListException</tt> exception is thrown.
	 */
	public void addNode(String address,XBeeNode node) throws XBeeNodeException{
		
		logger.debug("Try to add a new node. Addr:"+address);
		
		if(node.getAddress64String() != null){
			
			if(!list.containsKey(address)){
				list.put(address,node);
			}
			else
				throw new XBeeNodeException("NodeAlreadyOnListException");
			
			if(node.getType() == DeviceType.COORDINATOR)
				this.coordinator = node;
		}
		else
			throw new XBeeNodeException("XBeeNodeAddressNotFoundException");
	}
	
	/**
	 * Remove a the node with the specified address.
	 * @param address The address of the node to be removed
	 * @throws XBeeNodeException Thrown an <tt>AddressNotInListException</tt> if the address isn't present on the list.
	 */
	public void removeNode(String address) throws XBeeNodeException{
		if(list.remove(address) == null)
			throw new XBeeNodeException("AddressNotInListException");
	}
	/**
	 * Remove a specified node on the list
	 * @param node The Node object of the node to be removed (always search the node on the list with the address provided inside the node)
	 * @throws XBeeNodeException Thrown an <tt>AddressNotInListException</tt> if the address isn't present on the list.
	 */
	public void removeNode(XBeeNode node) throws XBeeNodeException{
		this.removeNode(node.getAddress64String());
	}
	/**
	 * Check if the address privided is in the node list
	 * @param address To be searched
	 * @return <tt>true</tt> if the device is present, <tt>false</tt> otherwise.
	 */
	public boolean isPresent(String address){
		return list.containsKey(address);
	}
	/**
	 * Check if the node is on the list searching my node address
	 * @param node The node to search.
	 * @return <tt>true</tt> if the device is present, <tt>false</tt> otherwise.
	 */
	public boolean isPresent(XBeeNode node){
		return this.isPresent(node.getAddress64String());
	}
	/**
	 * Get the XBeeNode of a specified node address
	 * @param address The address of the searched node
	 * @return The Node searched
	 */
	public XBeeNode getNode(String address){
		return this.list.get(address);
		
	}
	
	//TODO testing methods
	public XBeeNode[] getAllNodes(){
		//int listLength = list.
		XBeeNode[] nodes;
		int i=0;
		if(!list.isEmpty()){
			XBeeNode node;
			String key;
			Set<String> addressKeys = new HashSet<String>(); 
			
			addressKeys = list.keySet();
			nodes = new XBeeNode[addressKeys.toArray().length];
			Iterator<String> iterator = addressKeys.iterator();
			while(iterator.hasNext()){
				key = (String) iterator.next();
				node = list.get(key);
				if(node != null){
					nodes[i] = node;
					i++;
				}
				
			}
			return nodes;
		}
		return null;
		
	}
	
	/**
	 * Update information on a node present on the list
	 * @param node The node to update.
	 */
	public void updateNode(XBeeNode node){
		if(isPresent(node)){
			logger.debug("Node present on list: Updating...");
			list.put(node.getAddress64String(), node);
			logger.debug("Node updated");
		}
		else
			logger.error("Device not on list, i cannot udate this node.");
	}
	/**
	 * Get the Coordinator node of the list
	 * @return The XBeeNode of the Coordinator device
	 */
	public XBeeNode getCoordinatorNode(){
		if(coordinator != null)
			return coordinator;
		else return null;
	}
	
	/**
	 * Set inactive flag in all devices on this list. Used for know if the devices are sleeping
	 * or not present.
	 */
	protected void setAllInactive(){
		if(!list.isEmpty()){
			XBeeNode node;
			String key;
			Set<String> addressKeys = new HashSet<String>(); 
			addressKeys = list.keySet();
			Iterator<String> iterator = addressKeys.iterator();
			while(iterator.hasNext()){
				key = (String) iterator.next();
				node = list.get(key);
				node.setActive(false);
				list.put(key, node);
			}
		}
	}
	/**
	 * Search the Coordinator device on the list.
	 * @return The XbeeNode corresponding to the Coordinator
	 */
	protected XBeeNode searchCoordinator(){
		if(!list.isEmpty()){
			XBeeNode node;
			String key;
			Set<String> addressKeys = new HashSet<String>(); 
			addressKeys = list.keySet();
			Iterator<String> iterator = addressKeys.iterator();
			while(iterator.hasNext()){
				key = (String) iterator.next();
				node = list.get(key);
				if(node.getType() == DeviceType.COORDINATOR){
					this.coordinator = node; //Save the coordinator Node on list for future use
					return node; //Save the coordinator Node on list for future use
				}
			}
		}
		return null;
	}
	

}
